
/* GCSx
** MAIN.CPP
**
** Startup and exception catching
*/

/*****************************************************************************
** Copyright (C) 2003-2006 Janson
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
*****************************************************************************/

#include "all.h"

void gcsxTerminate() {
    fatalCrash(0, "(unknown error- terminate() called)");
}

void gcsxUnexpected() {
    fatalCrash(0, "(unknown error- unexpected() called)");
}

void doAllCleanup() {
    try { beginExitStage(); } catch (...) { }
    try { clearEvents(); } catch (...) { }
    try { clipboardClear(); } catch (...) { }
    try { if (desktop) delete desktop; } catch (...) { }

    desktop = NULL;
        
    try { exitDebug(); } catch (...) { }
    try { closeFont(); } catch (...) { }
    try { exitVideo(); } catch (...) { }
    try { SDL_Quit(); } catch (...) { }
    
    try { if (config) delete config; } catch (...) { }
    try { if (mainDir) delete mainDir; } catch (...) { }
    try { if (resourceDir) delete resourceDir; } catch (...) { }
    try { ResolutionDialog::destroy(); } catch (...) { }
    try { TileSetPropertiesDialog::destroy(); } catch (...) { }
    try { RGBSelect::destroy(); } catch (...) { }
    try { ScenePropertiesDialog::destroy(); } catch (...) { }
    try { LayerPropertiesDialog::destroy(); } catch (...) { }
    try { AnimGroupPropertiesDialog::destroy(); } catch (...) { }
    try { ScriptPropertiesDialog::destroy(); } catch (...) { }
    try { SpawnPropertiesDialog::destroy(); } catch (...) { }
    try { WorldPropertiesDialog::destroy(); } catch (...) { }
    try { ImportImgDialog::destroy(); } catch (...) { }
    try { ImageSelect::destroyGlobals(); } catch (...) { }
    try { destroyFileDialogGlobals(); } catch (...) { }
    try { destroyConsoleGlobals(); } catch (...) { }
    try { Tokenizer::destroyGlobals(); } catch (...) { }

    config = NULL;
    mainDir = NULL;
    resourceDir = NULL;
}

int main(int argc, char *argv[]) {
    int retValue = 0;

    set_terminate(gcsxTerminate);
    set_unexpected(gcsxUnexpected);
#ifdef MEMDEBUG
    enableMemListTrack();
#endif

    // Catch all fatal exceptions
    try {
        // Catch exceptions from startup
        try {
            // For bytecode
            vPtrSize = sizeof(void*) / sizeof(Uint32);
            if (sizeof(void*) % sizeof(Uint32)) ++vPtrSize;

            bcFloatSize = sizeof(BCfloat) / sizeof(Uint32);
            if (sizeof(BCfloat) % sizeof(Uint32)) ++bcFloatSize;
            
            // Assert that long long is 48bits+
            // Other types are asserted in SDL_types.h
            if (sizeof(long long) < 6) {
                fatalCrash(1, "Integer type of 48 or more bits not available");
            }
            
            // Debugging/console
            initDebugBuffer();
            
            // Version identifier
            debugWrite(DEBUG_VERSION, PRODUCT_NAME " version %d.%d.%d.%d", VER_MAJOR, VER_MINOR, VER_RELEASE, VER_BUILD);
            
            // Global objects with minimal initialization
            config = new Config();
            
            // Determine main/resource directories
            mainDir = new string;
            resourceDir = new string;
            getPathname(argv[0], *mainDir);
            createDirname(mainDir->c_str(), "resource", *resourceDir);
        
            // Initialize SDL
            initVideo();
            
            // OpenGL tests
            selectVideoMode(640, 480, -1, 0, 0, 1);
            oglTestCapabilities();

            // Initialize default video mode
            initDefaultVideo();
            
            // Other misc. initializations
            prepareFont();
            initDebugWindow();
            screenFlip();
            fillInterpreterTables();
           
            // (default to this stuff off; this also seems to jumpstart a few things
            //  for example Alt+F4 doesn't seem to work without these initializing lines)
            SDL_EnableKeyRepeat(0, 0);
            SDL_EnableUNICODE(0);

            // Create global desktop object
            desktop = new Desktop;
        }
        // Deal with exceptions from startup
        catch (const BaseException& e) {
            doAllCleanup();
            // Any exception from start is fatal and we definately can't use our
            // GUI, so just use platform-specific alert box
            systemErrorBox(e.details, "Startup Error");
            return -1;
        }
        // (any non-gcsx exception- not likely)
        catch (...) {
            doAllCleanup();
            // Any exception from start is fatal and we definately can't use our
            // GUI, so just use platform-specific alert box
            systemErrorBox("Unhandled exception on startup!", "Startup Error");
            return -1;
        }
    
        // Start front end
        gcsxFrontEnd();
    }
    // Temporary catch-all exceptions
    // Our exceptions
    catch (BaseException& e) {
        beginExitStage();

        int didntGui = 0;
        try {
            // Use our own GUI here to display error
            guiErrorBox(string(e.details), errorTitleException);
        }
        catch (...) {
            didntGui = 1;
        }
        
        doAllCleanup();

        if (didntGui) {
            // We didn't do a GUI error
            systemErrorBox(e.details, "Internal Exception");
        }
        retValue = -1;
    }
    // C++ exceptions
    catch (const exception& e) {
        doAllCleanup();
        // Don't use our GUI, we don't know what caused this exception
        systemErrorBox(e.what(), "GCC Exception");
        retValue = -1;
    }
    // Other exceptions?
    catch (...) {
        doAllCleanup();
        // Don't use our GUI, we don't know what caused this exception
        systemErrorBox("(unknown error)", "Unhandled Exception");
        retValue = -1;
    }

    // Cleanup (some duplicate cleanup may occur if an exception occurred-
    // this is safe)
    doAllCleanup();
    
#ifdef MEMDEBUG
    memLeakCheck();
    if (memDebugAnyErrors()) {
        systemErrorBox("One or more memory errors or leaks occurred- please check stdout.txt", "Memory Exception");
    }
#endif
    
    return retValue;
}

